import json
import re
import time
import types
from typing import List
import logging
from apiTest.models import TestCase, TestCaseStep, TestCaseGroup, ApiRequestResult, TestCaseProcessor
from apiTest.send_http_request import execute_api_case, GetExtractions
from apiTest.serializers import ApiRequestResultModelSerializer, TestCaseResultModelSerializer, \
    TestCaseStepModelSerializer, TestCaseGroupResultModelSerializer, \
    TestCaseGroupModelSerializer, TestCaseProcessorModelSerializer
from system.models import DBConnection
from system.mysql_con import mysql_connection
from system.serializers import DBConnectionModelSerializer

logging = logging.getLogger("log")


class TestCaseResultDto:
    def __init__(self, test_case_result: dict, api_request_result_list: list, case_name: str):
        self.test_case_result = test_case_result
        self.api_request_result_list = api_request_result_list
        self.case_name = case_name


class TestCaseGroupResultDto:
    def __init__(self, test_case_group_result: dict, test_case_result_dto: TestCaseResultDto):
        self.test_case_group_result = test_case_group_result
        self.test_case_result_dto = test_case_result_dto


def tes_case_run(test_case_id: int, env_id: int) -> TestCaseResultDto:
    """
    测试用例执行核心代码
    :param test_case_id:
    :param env_id:
    :return: 测试用例结果
    """
    test_case_result_dto = step_run(test_case_id, env_id)
    serializer = TestCaseResultModelSerializer(data=test_case_result_dto.test_case_result)
    if serializer.is_valid():
        serializer.save()
        test_case_result_dto.test_case_result = serializer.data
    else:
        print(serializer.errors)
    test1 = []
    for api_request_result in test_case_result_dto.api_request_result_list:
        # 将接口结果保存至表中
        serializer = ApiRequestResultModelSerializer(data=api_request_result)
        if serializer.is_valid():
            api_request_result_models = serializer.save()
            # api_request_result_models = ApiRequestResult.objects.get(id=api_request_result_models.id)
            # api_request_result_models = api_request_result_models.as_dict()
            test1.append(serializer.data)
        else:
            print(serializer.errors)
    test_case_result_dto.api_request_result_list = test1
    return test_case_result_dto


def group_run(test_case_group_id: int, env_id: int, task_log_id=0) -> TestCaseGroupResultDto:
    """
    测试用例组执行核心代码
    :param test_case_group_id:
    :param env_id:
    :param task_log_id:
    :return: 测试用例组结果
    """
    test_case_result_dto = TestCaseResultDto
    test_case_pass_result = 0
    test_case_failed_result = 0
    test_case_skip_result = 0
    test_case_group = TestCaseGroup.objects.get(id=test_case_group_id, is_deleted=0)
    test_case_group_model = TestCaseGroupModelSerializer(test_case_group).data
    test_case_ids = TestCaseGroupModelSerializer(test_case_group).data["test_case_merge"]
    test_case_count_result = len(test_case_ids)
    for test_case_id in test_case_ids:
        test_case_model = TestCase.objects.all().get(id=test_case_id)
        if test_case_model.is_skip:
            test_case_skip_result += 1
        else:
            test_case_result_dto = step_run(test_case_id, env_id)
            if test_case_result_dto.test_case_result["step_fail_results"] > 0:
                test_case_failed_result += 1
            else:
                test_case_pass_result += 1
    test_case_group_result = {
        "task_log_id": task_log_id,
        "test_case_ids": str(test_case_ids),
        "test_case_group_id": test_case_group_id,
        "test_case_group_name": test_case_group_model["name"],
        "test_case_count_result": test_case_count_result,
        "test_case_pass_result": test_case_pass_result,
        "test_case_failed_result": test_case_failed_result,
        "test_case_skip_result": test_case_skip_result
    }
    group_serializer = TestCaseGroupResultModelSerializer(data=test_case_group_result)
    if group_serializer.is_valid():
        group_serializer.save()
    else:
        print(group_serializer.errors)
    # test_case_result_dto = json.dumps(test_case_result_dto.__dict__, ensure_ascii=False)
    # test_case_result_dto = json.loads(test_case_result_dto)
    test_case_group_result_dto = TestCaseGroupResultDto(test_case_group_result, test_case_result_dto)
    return test_case_group_result_dto


def step_run(test_case_id: int, env_id: int) -> TestCaseResultDto:
    """
    测试用例步骤执行核心代码
    :param test_case_id:
    :param env_id:
    :return: 测试用例结果
    """
    get_extractions_list: List[GetExtractions] = []
    api_request_result_list = []
    test_case_result = {}
    step_pass = 0
    step_count = 0
    step_fail = 0
    api_test_case_steps = TestCaseStep.objects.all().filter(test_case_id=test_case_id, is_deleted=0).order_by("sort")
    test_case = TestCase.objects.all().get(id=test_case_id, is_deleted=0)
    api_test_case_steps = TestCaseStepModelSerializer(api_test_case_steps, many=True).data
    start_time = time.time()
    # step_list 处理
    for step in api_test_case_steps:
        step['env_id'] = env_id
        step["project_id"] = test_case.project_id
        # 前置处理器
        result_extraction_list = []
        test_case_processor_list = TestCaseProcessor.objects.filter(step_id=step["id"], processor_type=0)
        test_case_processor_list = TestCaseProcessorModelSerializer(test_case_processor_list, many=True).data
        test_case_processor_run_list = test_case_processor_run(test_case_processor_list)
        for get_extractions in test_case_processor_run_list:
            get_extractions_list.append(get_extractions)
            result_extraction_list.append(get_extractions.to_dict())
        api_request_result = execute_api_case(step, get_extractions_list)
        # 后置处理器
        test_case_processor_list = TestCaseProcessor.objects.filter(step_id=step["id"], processor_type=1)
        test_case_processor_list = TestCaseProcessorModelSerializer(test_case_processor_list, many=True).data
        test_case_processor_run_list = test_case_processor_run(test_case_processor_list)
        # 处理结果提取参数给步骤使用
        for get_extractions in test_case_processor_run_list:
            get_extractions_list.append(get_extractions)
            # 将后置处理器获取的get_extractions_list 转为result_extractions展示在提取参数中
            result_extraction_list.append(get_extractions.to_dict())
        # get_extractions_list.extend(test_case_processor_run(test_case_processor_list, 1))
        if api_request_result.get('result_extractions'):
            for result_extraction in json.loads(api_request_result['result_extractions']):
                get_extractions_list.append(GetExtractions.from_string(result_extraction))
                # 将前置处理器获取的get_extractions_list 转为result_extractions展示在提取参数中
                result_extraction_list.append(json.loads(api_request_result.get('result_extractions')))
        api_request_result['result_extractions'] = result_extraction_list
        api_request_result["api_id"] = step["api_id"]
        api_request_result["test_case_id"] = test_case_id
        api_request_result["api_test_case_step_id"] = step["id"]
        api_request_result_list.append(api_request_result)
        step_count += 1
        if api_request_result.get("result_is_pass"):
            step_pass += 1
        else:
            step_fail += 1
    end_time = time.time()
    milliseconds = int((end_time - start_time) * 1000)
    test_case_result["test_case_id"] = test_case_id
    test_case_result["test_case_name"] = test_case.name
    test_case_result["step_count_results"] = step_count
    test_case_result["step_pass_results"] = step_pass
    test_case_result["step_fail_results"] = step_fail
    test_case_result["test_run_time"] = milliseconds
    test_case_result_dto = TestCaseResultDto(test_case_result, api_request_result_list, test_case.name)
    return test_case_result_dto


def test_case_processor_run(test_case_processor_list):
    """
    处理器功能
    :param test_case_processor_list:
    """
    get_extractions_list: List[GetExtractions] = []
    if len(test_case_processor_list) > 0:
        for test_case_processor in test_case_processor_list:
            if test_case_processor["content"] and test_case_processor["type"] == 1:
                db_connection = DBConnection.objects.get(id=test_case_processor["db_connection_id"])
                db_connection = DBConnectionModelSerializer(db_connection).data
                results = mysql_connection(db_connection).select(sql=test_case_processor["content"])
                # 用别称来当作extract_name
                pattern = re.compile(r'as\s+(\w+)')
                matches = pattern.findall(test_case_processor["content"])
                if results:
                    for i in range(0, matches.__len__()):
                        get_extractions = GetExtractions(matches[i],
                                                         "from db", results[0][i], True)
                        get_extractions_list.append(get_extractions)
            elif test_case_processor["content"] and test_case_processor["type"] == 0:
                # 创建一个空的命名空间来执行脚本
                namespace = {}
                result = exec(test_case_processor["content"], namespace)
                # 检查函数是否已被定义
                if 'py_script' in namespace and isinstance(namespace['py_script'], types.FunctionType):
                    # 调用函数并获取结果
                    result = namespace['py_script']('str_value')  # 传递一个自定义值作为参数
                logging.info(f"脚本运行获取结果：{result}")

    return get_extractions_list
